﻿// ----------------------------------------------------------------------------------
// <copyright file="SimpleIocContainerTest.cs" company="Christopher Hines">
// Copyright (c) 2012 All Right Reserved
// </copyright>
// <author>Chris Hines</author>
// <date>2012-03-23</date>
// <summary>
//     Provides an example of using the framework without a standard IoC container
// </summary>
// ----------------------------------------------------------------------------------

namespace Copperfield.UseCases.Test
{
    using Copperfield;
    using Copperfield.Demo.Common;
    using Copperfield.Demo.Models;
    using Copperfield.Sdk;

    using FluentAssertions;

    using Microsoft.VisualStudio.TestTools.UnitTesting;

    /// <summary>
    /// Provides an example of using the framework without a standard IoC container
    /// </summary>
    [TestClass]
    public class SimpleIocContainerTest
    {
        /// <summary>
        /// Gets or sets the test context
        /// </summary>
        /// <value>
        /// The test context
        /// </value>
        public TestContext TestContext { get; set; }

        /// <summary>
        /// Gets or sets the test context
        /// </summary>
        /// <value>
        /// The test context
        /// </value>
        public TestContext Context { get; set; }

        /// <summary>
        /// Gets or sets the context manager
        /// </summary>
        /// <value>
        /// The context manager
        /// </value>
        private static ContextManagerBase<SignContext> ContextManager { get; set; }

        /// <summary>
        /// Initializes the test class
        /// </summary>
        /// <param name="testContext">
        /// The test context.
        /// </param>
        [ClassInitialize]
        public static void ClassInitialization(TestContext testContext)
        {
            // Wire-up for the minimal dependency injection available without a standard IoC container
            SimpleIocContainer.For<ContextManagerBase<SignContext>>().Use(new NonWebContextManager<SignContext>());
            SimpleIocContainer.For<DefaultSign>().Use(new DefaultSign());
            SimpleIocContainer.For<SpeedLimitSign>().Use(new SpeedLimitSign());
            SimpleIocContainer.For<HospitalSign>().Use(new HospitalSign());
            SimpleIocContainer.For<PedestrianWarningSign>().Use(new PedestrianWarningSign());
            SimpleIocContainer.For<RailroadCrossingSign>().Use(new RailroadCrossingSign());
            SimpleIocContainer.For<StopSign>().Use(new StopSign());

            // Configure how the framework can resolve an instance given a specific type of object
            CopperfieldConfiguration.InstancesAreResolvedBy(SimpleIocContainer.GetInstance);

            // Configure how the framework can resolve 
            CopperfieldConfiguration.ConfigurePluginInstances((pluginType, contextType, iocResolutionDelegate) =>
                SimpleIocContainer.DefineRetrievalOverride(pluginType, () => iocResolutionDelegate(pluginType, contextType)));

            ContextManager = SimpleIocContainer.GetInstance<ContextManagerBase<SignContext>>();
        }

        /// <summary>
        /// A unit test for a pedestrian sign
        /// </summary>
        [TestMethod]
        public void Simple_IoC_DefaultSignTest()
        {
            SetContext(SignColor.Unknown, SignShape.Unknown, SignText.Unknown);

            var sign = SimpleIocContainer.GetInstance<IStreetSign>();

            sign.Should().BeOfType<DefaultSign>();
        }

        /// <summary>
        /// A unit test for a speed limit sign
        /// </summary>
        [TestMethod]
        public void Simple_IoC_SpeedLimitSignTest()
        {
            SetContext(SignColor.White, SignShape.Rectangle, SignText.SpeedLimit);

            var sign = SimpleIocContainer.GetInstance<IStreetSign>();

            sign.Should().BeOfType<SpeedLimitSign>();
        }

        /// <summary>
        /// A unit test for a pedestrian sign
        /// </summary>
        [TestMethod]
        public void Simple_IoC_HospitalSignTest()
        {
            SetContext(SignColor.Blue, SignShape.Rectangle, SignText.Hospital);

            var sign = SimpleIocContainer.GetInstance<IStreetSign>();

            sign.Should().BeOfType<HospitalSign>();
        }

        /// <summary>
        /// A unit test for a pedestrian sign
        /// </summary>
        [TestMethod]
        public void Simple_IoC_StopSignTest()
        {
            SetContext(SignColor.Red, SignShape.Octagon, SignText.Stop);

            var sign = SimpleIocContainer.GetInstance<IStreetSign>();

            sign.Should().BeOfType<StopSign>();
        }

        /// <summary>
        /// A unit test for a pedestrian sign
        /// </summary>
        [TestMethod]
        public void Simple_IoC_RailroadCrossingSignTest()
        {
            SetContext(SignColor.Yellow, SignShape.Circle, SignText.Railroad);

            var sign = SimpleIocContainer.GetInstance<IStreetSign>();

            sign.Should().BeOfType<RailroadCrossingSign>();
        }

        /// <summary>
        /// A unit test for a pedestrian sign
        /// </summary>
        [TestMethod]
        public void Simple_IoC_PedestrianSignTest()
        {
            SetContext(SignColor.Yellow, SignShape.Square, SignText.Pedestrians);

            var sign = SimpleIocContainer.GetInstance<IStreetSign>();

            sign.Should().BeOfType<PedestrianWarningSign>();
        }

        /// <summary>
        /// Sets the sign context values
        /// </summary>
        /// <param name="color">
        /// The color.
        /// </param>
        /// <param name="shape">
        /// The shape.
        /// </param>
        /// <param name="signText">
        /// The sign text.
        /// </param>
        private static void SetContext(SignColor color, SignShape shape, string signText)
        {
            var context = ContextManager.GetContext() ?? new SignContext();

            context.Color = color;
            context.Shape = shape;
            context.Text = signText;

            ContextManager.SetContext(context);
        }
    }
}
